package com.huiyujinrong.qiangdanbao.utils;

import org.json.JSONException;
import org.json.JSONObject;

import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Random;
import java.util.UUID;

public class AliPayOderInfo {
    private Map<String,String> orderParamMap;
    private String privateKey;
    private boolean isRsa2;
    private AliPayOderInfo(Build build){
        this.orderParamMap = build.orderParamMap;
        this.privateKey = build.privateKey;
        this.isRsa2 = build.isRsa2;
    }
    public String getOrderInfo(){
        String orderInfoParam = getOrderInfoParam();
        String sign = getSign(orderParamMap,privateKey,isRsa2);
        return orderInfoParam + "&" + sign;
    }
    public static Build build(){
        return new Build();
    }

    private String getOrderInfoParam(){
        List<String> keys = new ArrayList<String>(orderParamMap.keySet());
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < keys.size() - 1; i++) {
            String key = keys.get(i);
            String value = orderParamMap.get(key);
            sb.append(buildKeyValue(key, value, true));
            sb.append("&");
        }
        String tailKey = keys.get(keys.size() - 1);
        String tailValue = orderParamMap.get(tailKey);
        sb.append(buildKeyValue(tailKey, tailValue, true));
        return sb.toString();
    }

    public String getSign(Map<String, String> map, String rsaKey, boolean rsa2) {
        List<String> keys = new ArrayList<String>(map.keySet());
        // key排序
        Collections.sort(keys);

        StringBuilder authInfo = new StringBuilder();
        for (int i = 0; i < keys.size() - 1; i++) {
            String key = keys.get(i);
            String value = map.get(key);
            authInfo.append(buildKeyValue(key, value, false));
            authInfo.append("&");
        }

        String tailKey = keys.get(keys.size() - 1);
        String tailValue = map.get(tailKey);
        authInfo.append(buildKeyValue(tailKey, tailValue, false));

        String oriSign = SignUtils.sign(authInfo.toString(), rsaKey, rsa2);
        String encodedSign = "";

        try {
            encodedSign = URLEncoder.encode(oriSign, "UTF-8");
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }
        return "sign=" + encodedSign;
    }


    private String buildKeyValue(String key, String value, boolean isEncode) {
        StringBuilder sb = new StringBuilder();
        sb.append(key);
        sb.append("=");
        if (isEncode) {
            try {
                sb.append(URLEncoder.encode(value, "UTF-8"));
            } catch (UnsupportedEncodingException e) {
                sb.append(value);
            }
        } else {
            sb.append(value);
        }
        return sb.toString();
    }

    public static class Build{
        private Build(){}
        String appId;
        boolean isRsa2;
        float money;
        String privateKey;
        Map<String, String>  orderParamMap;
        String passBack;
        String notifyUrl;
        String subject;
        String body;
        public Build setAppId(String appId) {
            this.appId = appId;
            return this;
        }

        public Build setRsa2(boolean rsa2) {
            isRsa2 = rsa2;
            return this;
        }

        public Build setMoney(float money) {
            this.money = money;
            return this;
        }

        public Build setPassback(String passBack) {
            this.passBack = passBack;
            return this;
        }

        public Build setNotifyUrl(String notifyUrl) {
            this.notifyUrl = notifyUrl;
            return this;
        }

        public Build setPrivateKey(String privateKey) {
            this.privateKey = privateKey;
            return this;
        }

        public Build setBody(String body) {
            this.body = body;
            return this;
        }

        public Build setSubject(String subject) {
            this.subject = subject;
            return this;
        }

        public AliPayOderInfo builder() throws AliPayOderInfoException {
            if(appId == null){
                throw new AliPayOderInfoException("请填写参数APPID");
            }
            if(passBack == null){
                throw new AliPayOderInfoException("请填写参数-pssBack-回调参数");
            }
            if(notifyUrl == null){
                throw new AliPayOderInfoException("请填写参数-notifyUrl-回调地址");
            }
            if(privateKey == null){
                throw new AliPayOderInfoException("请填写参数-privateKey-签名");
            }
            if(subject == null){
                throw new AliPayOderInfoException("请填写参数-subject-商品标题");
            }
            if(body == null){
                throw new AliPayOderInfoException("请填写参数-body-商品描述信息");
            }
            createOrderParamMap();
            return new AliPayOderInfo(this);
        }

        private void createOrderParamMap(){
            orderParamMap = new HashMap<>();
            orderParamMap.put("app_id", appId);
            orderParamMap.put("biz_content",createBizContent());
            orderParamMap.put("charset","utf-8");
            orderParamMap.put("method","alipay.trade.app.pay");
            orderParamMap.put("sign_type",isRsa2 ? "RSA2" : "RSA");
            orderParamMap.put("timestamp","2016-07-29 16:55:53");
            orderParamMap.put("version","1.0");
        }
        private String createBizContent(){
            JSONObject job = new JSONObject();
            try {
                job.put("timeout_express","30m");
                job.put("product_code","QUICK_MSECURITY_PAY");
                job.put("total_amount",String.format("%.2f",money));
                job.put("subject",subject);
                job.put("body",body);
                job.put("out_trade_no", UUID.randomUUID().toString());
                job.put("passback_params",passBack);
                job.put("notify_url",notifyUrl);
            } catch (JSONException e) {
                e.printStackTrace();
            }
            return job.toString();
        }
        private String getOutTradeNo() {
            SimpleDateFormat format = new SimpleDateFormat("MMddHHmmss", Locale.getDefault());
            Date date = new Date();
            String key = format.format(date);
            Random r = new Random();
            key = key + r.nextInt();
            key = key.substring(0, 15);
            return key;
        }
    }
    public static class AliPayOderInfoException extends RuntimeException{
        public AliPayOderInfoException(String msg){
            super(msg);
        }
    }
}
